/*******************************************************************************
  * Copyright (c) 2013 E.W.Clay.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *******************************************************************************/ 

#pragma once

#include <cstddef>

namespace Ut
{

void DebugBreak();

uint64 GetTime();
float GetMs(uint64 interval);

template <typename T>
const T& Clamp(const T& value, const T& lo, const T& hi)
{
	return value < lo ? lo : hi < value ? hi : value;
}

template <typename T>
const T& Max(const T& a, const T& b)
{
	return a < b ? b : a;
}

template <typename T>
const T& Min(const T& a, const T& b)
{
	return b < a ? b : a;
}

template <typename T>
T Sign(const T& t)
{
	return (t >= T(0)) ? T(1) : T(-1);
}

inline uint32 AlignUp(uint32 i, uint32 align)
{
	return (i + align - 1) - (i + align - 1) % align;
}

inline uint32 AlignDown(uint32 i, uint32 align)
{
	return i - i % align;
}

template <typename Iterator_t>
class Range
{
public:
	typedef typename Iterator_t Iterator;

	Range() {}
	Range(const Iterator& b, const Iterator& e) : m_begin(b), m_end(e) {}
	
	const Iterator& begin() const {return m_begin;}
	const Iterator& end() const {return m_end;}

	bool empty() const {return m_begin == m_end;}

private:
	Iterator m_begin;
	Iterator m_end;
};

template <typename Iterator_t>
Range<Iterator_t> MakeRange(const Iterator_t& b, const Iterator_t& e)
{
	return Range<Iterator_t>(b, e);
}

template <typename Iterator_t>
inline bool operator == (const Range<Iterator_t>& a, const Range<Iterator_t>& b)
{
	return a.begin() == b.begin() && a.end() == b.end();
}

template <typename T, std::size_t N = 16>
class AlignmentAllocator 
{
public:
	typedef T value_type;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;

	typedef T * pointer;
	typedef const T * const_pointer;

	typedef T & reference;
	typedef const T & const_reference;

	inline pointer allocate(size_type n) 
	{
		return (pointer) _aligned_malloc(n * sizeof(T), N);
	}

	inline void deallocate(pointer p, size_type) 
	{
		_aligned_free(p);
	}

	inline void construct(pointer p, const_reference t) 
	{
		new (p) T(t);
	}

	inline void destroy(pointer p) 
	{
		p->~T();
	}

	inline size_type max_size() const 
	{
		return size_type(-1) / sizeof(value_type);
	}

	template <typename T2>
	struct rebind 
	{
		typedef AlignmentAllocator<T2, N> other;
	};

	bool operator!=(const AlignmentAllocator<T, N>& other) const  
	{
		return !(*this == other);
	}

	bool operator==(const AlignmentAllocator<T, N>& other) const 
	{
		return true;
	}
};

}

//#ifdef  NDEBUG
#if 0

#define Assert(_Expression)

#else

#define Assert(_Expression) if ((_Expression) == 0) Ut::DebugBreak();

#endif